// MyFamily - XML based genealogy program.
// Copyright (C) 2006  Doug Swisher
// See the file COPYING.txt for license details.

using System;
using System.Collections.Generic;
using System.Text;

using NUnit.Framework;


namespace DataModel
{
    public class GedComLine
    {
        private int lineNumber;
        private int level;
        private string tag;
        private string value;
        private string xref;

        private enum States { WaitingForLevel, InLevel, WaitingForXrefOrTag, InXref, WaitingForTag, InTag, WaitingForValue, InValue };


        public static GedComLine CreateTop()
        {
            return new GedComLine(-1, "MYF", null, null, -1);
        }


        public static GedComLine Parse(string line, int lineNumber)
        {
            StringBuilder level = new StringBuilder();
            StringBuilder tag = new StringBuilder();
            StringBuilder value = new StringBuilder();
            StringBuilder xref = new StringBuilder();
            States state = States.WaitingForLevel;

            foreach (char c in line)
            {
                switch (state)
                {
                    case States.WaitingForLevel:
                        if (char.IsDigit(c))
                        {
                            level.Append(c);
                            state = States.InLevel;
                        }
                        break;


                    case States.InLevel:
                        if (char.IsDigit(c))
                            level.Append(c);
                        else
                            state = States.WaitingForXrefOrTag;
                        break;


                    case States.WaitingForXrefOrTag:
                        if (c == '@')
                        {
                            xref.Append(c);
                            state = States.InXref;
                        }
                        else if (char.IsLetterOrDigit(c) || (c == '_'))
                        {
                            tag.Append(c);
                            state = States.InTag;
                        }
                        break;


                    case States.InXref:
                        if (char.IsLetterOrDigit(c) || (c == '@'))
                            xref.Append(c);
                        else
                            state = States.WaitingForTag;
                        break;


                    case States.WaitingForTag:
                        if (char.IsLetterOrDigit(c))
                        {
                            state = States.InTag;
                            tag.Append(c);
                        }
                        break;


                    case States.InTag:
                        if (char.IsLetterOrDigit(c) || (c == '_'))
                            tag.Append(c);
                        else
                            state = States.WaitingForValue;
                        break;


                    case States.WaitingForValue:
                        if (!char.IsWhiteSpace(c))
                        {
                            value.Append(c);
                            state = States.InValue;
                        }
                        break;


                    case States.InValue:
                        value.Append(c);
                        break;
                }
            }

            int lev = 0;
            try
            {
                lev = int.Parse(level.ToString());
            }
            catch (FormatException)
            {
                return null;
            }

            GedComLine gedComLine = new GedComLine(lev, tag.ToString(), value.ToString(), xref.ToString(), lineNumber);

            return gedComLine;
        }



        private GedComLine(int level, string tag, string value, string xref, int lineNumber)
        {
            this.level = level;
            this.tag = tag;
            this.value = value;
            this.xref = xref;
            this.lineNumber = lineNumber;
        }


        public int LineNumber
        {
            get { return this.lineNumber; }
        }

        public int Level
        {
            get { return this.level; }
        }

        public string Value
        {
            get { return this.value; }
        }

        public string Xref
        {
            get { return this.xref; }
        }

        public string Tag
        {
            get { return this.tag; }
        }

    }



    [TestFixture]
    public class GedComLineTests
    {
        // TODO - add some tests!
    }

}
